package com.upcoming.elasticsearchstudy.controller;

import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@RestController
public class ElasticCotroller {

    @Autowired
    public TransportClient client;

    @GetMapping("/")
    public String index() {
        return "index";
    }


    @GetMapping("/index/search")
    public ResponseEntity getIndex(String id) {
        GetResponse response = this.client.prepareGet("book", "novel", id).get();
        if (!response.isExists()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity(response.getSource(), HttpStatus.OK);
    }

    @PostMapping("add/book/novel")
    public ResponseEntity addDoc(@RequestParam(name = "title") String title,
                                 @RequestParam(name = "author") String author,
                                 @RequestParam(name = "word_count") int wordCount,
                                 @RequestParam(name="publish_date")
                                     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date publishDate) {
        try {
            XContentBuilder context = XContentFactory.jsonBuilder()
                    .startObject()
                    .field("doc.title", title)
                    .field("doc.author", author)
                    .field("doc.word_count", wordCount)
                    .field("doc.publish_date", publishDate.getTime())
                    .endObject();
            IndexResponse response = this.client.prepareIndex("book", "novel").setSource(context).get();
            return new ResponseEntity(response.getId(), HttpStatus.OK);
        } catch (IOException e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
        }

    }

    @DeleteMapping("delete/book/novel")
    public ResponseEntity deleteBookNovel(@RequestParam("id") String id) {
        DeleteResponse response = this.client.prepareDelete("book", "novel", id).get();
        return new ResponseEntity(response.getResult().toString(), HttpStatus.OK);


    }

    @PutMapping("update/book/novel")
    public ResponseEntity updateBookNovel(@RequestParam("id") String id,
                                          @RequestParam(value = "title") String title) {
        UpdateRequest update = new UpdateRequest("book", "novel", id);
        try {
            XContentBuilder content =  XContentFactory.jsonBuilder()
                    .startObject()
                    .field("doc.title", title)
                    .endObject();
            update.doc(content);
            UpdateResponse response = this.client.update(update).get();
            return new ResponseEntity(response.getResult().toString(), HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
        }

    }

    @PostMapping("query/book/novel")
    public ResponseEntity queryBookNovel(@RequestParam("title") String title,
                                         @RequestParam("author") String author,
                                         @RequestParam(name = "gt_word_count", defaultValue = "0") int gtWordCount,
                                         @RequestParam(name="lt_word_count") Integer ltWordCount) {
        try {
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
            if (author != null) {
                boolQuery.must(QueryBuilders.matchQuery("doc.author", author));
            }
            if (title != null) {
                boolQuery.must(QueryBuilders.matchQuery("doc.title", title));
            }
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("doc.word_count")
                    .from(gtWordCount);
            if (ltWordCount != null && ltWordCount != 0) {
                rangeQuery.to(ltWordCount);
            }
            boolQuery.filter(rangeQuery);
            SearchRequestBuilder builder = this.client.prepareSearch("book")
                    .setTypes("novel")
                    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                    .setQuery(boolQuery)
                    .setFrom(0)
                    .setSize(10);
            System.out.println(builder);
            SearchResponse response = builder.get();
            List<Map<String, Object>> result = new ArrayList<>();
            for (SearchHit hit : response.getHits()) {
                result.add(hit.getSource());
            }
            return new ResponseEntity(result, HttpStatus.OK);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}
